[レポート]Content-Disposition の “filename” という地雷 -曖昧な要件が原因となる脆弱性- – CODE BLUE 2023 #codeblue_jp
こんにちは、AWS事業本部@福岡オフィスのべこみん(@beco_minn)です。
今回はCODE BLUE 2023で行われた以下のセッションのレポートです。
Content-Disposition の "filename" という地雷 -曖昧な要件が原因となる脆弱性-
Content-Disposition は、幅広く利用されるヘッダーの1つで、HTTP リクエストやレスポンス、メールの中で利用されている。 しかしながら、Content-Disposition のフィールドを定義する RFC には、フィールドの1つである filename の明確なエスケープ要件が定められておらず。そのため、多くのサービス、Webフレームワーク、ライブラリ、プログラミング言語(Python, Java)、ブラウザ(Firefox)でさえも脆弱性を有していた。 この曖昧な仕様を取り巻く課題は根深く、この仕様を原因とした脆弱性 / 脅威ベクタは、セキュリティコミュニティや、研究者ですらあまり認知されていない。 その結果、脆弱性の報告や修正は場当たり的に行われている状態にあります。 この講演では、数ヵ月にわたる研究から発見した Content-Disposition の filename, filename* のエスケープ不足が原因となる20 個ほどの脆弱性(ブラウザ(1個)、プログラミング言語(2個)、Webフレームワーク(6個)、 HTTP Client(5個) など)について取り上げ、この問題を取り巻く状況や、発生箇所による影響などについて発表を行う。
Presented by : 佐分 基泰 - Motoyasu Saburi
レポート
- ファイルアップローダーに対して
malicious.sh"; hoge="a,txt
をアップロードすると、txtがshellになる- これはメールクライアントなどでも起きる
- なので
"
をエスケープしないといけないが、Content-DispositionのRFCではスケープ要件が定義されていない
- 上記を知った背景は、Springで発生したパーサーエラー(IllegalArgumentException)
- ここでContent-Dispositionの存在を知った
- Content-Dispositionのmultipartとは
- boundaryと呼ばれる区切り文字で分かれている
- 書き方は
name="XXX"
というkey-value形式
- なぜエラーが発生したのか?
- 上記パーサーエラーの解説
- まず、入力値をtokenize()で値を分ける
;
で各key-valueのセットに分けられる
- その後、keyとvalueに分ける
- 最後にRFCにも定義されたメタデータかどうかをチェックする
- エラー発生の原因は「=が無いから」というもの
- 脆弱性を見つけるために
"
や;
を上手く使えば良さそう- 最終的にこのような入力値にした
a.sh";name="dummy";size=1234;dummy=".txt
- 実際どういう攻撃が想定されるか?
- ユーザーがファイルをアップロード出来るシステム
- 攻撃者がファイルの名前を変更出来ると仮定
- 1つのパートの中で同じキーを使う
- for-loopであれば同じキーがある場合、後のやつで上書きされる
- ただし、攻撃の条件は厳しい
- 攻撃者が被害者のファイル名のフォーム名をコントロール出来る必要がある
- ケースは想定しづらいが、例えば誰でも操作出来るwikiのページなど
- 攻撃者が被害者のファイル名のフォーム名をコントロール出来る必要がある
- 影響
- ファイル名、拡張子の変更
- nameフィールド以外の変更
- 上記をSpringに報告したところ、「誤った値を送っているFireFox側の問題じゃないか」と返ってきた
- FireFoxに報告したところ、脆弱性としてとして認められた
- 何かガイドラインに書いてないのか?
- 少なくとも現時点のRFCには書かれていない
- WHATWGには2021年に書かれた
"
→%22
、/r
→%0d
、/n
→%0a
にエスケープすると良い
- ただし、ここで問題が。。。FireFoxが報告した2019年から2021年まで2.5年間対応してくれなかった
- CVEも無し
- Spring側の報告で脆弱性の詳細が
- レスポンスヘッダーのContent-Dispositionの影響でRFDが起こる可能性があった
- RFDとは?
- Reflected File Download
- 攻撃者が作成したページにユーザーをアクセスさせたりして、悪意のあるファイルをダウンロードさせること
- Black Hatの資料
- Reflected File Download
- RFDの理解に取り組み始めた
- CRLFを意識してこの脆弱性を突く攻撃について考えてみた
- HTTP Clientなどでリクエストヘッダーに改行コードを複数入れると、ヘッダーの部分がズレてbodyとして判断されるようになる
- リクエスト
- リクエストの改ざん、バリデーションのバイパスが出来るのではないか
- レスポンス
- filenameにCRLFを入れるだけで簡単にCRLF injectionが出来そう
- 80ほどの様々なアプリやライブラリについてこの脆弱性があるか確認した
- 複数のクライアントアプリや言語、FWで発見された
- 報告すると対応してくれたところもあれば、未だに対応してくれないところもある
- 対応していないところは「そもそもこのような値がユーザーから渡されるべきではないので、これは脆弱性ではない」というスタンス
- Pythonにも存在した
- FWだとgolangのIrisにも
- Ktorでは
filename*
で発生- non-ASCIIファイル名のためのもの
- URL Encodeが必要
- まとめ
- Content-DispositionのエスケープはRFCでは未定義、WhatWGでは定義されている
- filenameの入力値は以下の3つをエスケープしよう
"
→%22
or/"
/r
→%0d
or//r
/n
→%0a
or//n
- filename*はRFCを遵守していれば問題無し
感想
Content-Dispositionを使う際に起こりうる脆弱性について学ぶことが出来ました。言語やアプリの開発側も見解が分かれているということからも、RFCなど共通のガイドラインで定義されていることは重要ですね。
エスケープ可能な場合、怪しい文字列はエスケープしたいですね。
参考: